# -*- coding: utf-8 -*-
###
# @Author: CPS
# @Date: 2020-07-24 16:10:47
# @Last Modified by: CPS
# @Last Modified time: 2020-09-20 22:09:05
# @file_path D:\CPS\IDE\3176x32 前端\Data\Packages\testt\stylusBeautify\stylus-beautify.py
# @Filename stylus-beautify.py
# 本插件90% 参考 CSScomb插件代码
###

import json
import os
import platform
import sublime
import sublime_plugin
from subprocess import Popen, PIPE

# 将当前所有缓冲区存入 tuple,获得可迭代的特性,往后能执行批量处理
sublime.Region.totuple = lambda self: (self.a, self.b)
sublime.Region.__iter__ = lambda self: self.totuple().__iter__()

# 拼接 nodejs插件的入口文件 stylus-beautify.js
NODE_SCRIPT_PATH = os.path.join(sublime.packages_path(),"testt","TesttBeautify","index.js")

#当前处理文件的格式
SYNTAX = False

# 判断是否存在 nodejs
HAS_NODE = False

def plugin_loaded():
    global HAS_NODE
    try:
        p = Popen(
            ['node', '-v'],
            stdout=PIPE,
            stdin=PIPE,
            stderr=PIPE
        )
    except Exception:
        HAS_NODE = False
        print("Couldn't find Node.js")
    else:
        res, err = p.communicate()
        if res:
            HAS_NODE = True
        else:
            HAS_NODE = False


##
## @brief      stylus 格式化
##
class TesttStylusBeauty(sublime_plugin.TextCommand):
    def run(self, edit):
        # 判断当前语法是否合法
        global SYNTAX
        SYNTAX = self.is_target()
        if not SYNTAX:
            return

        # 获取配置 默认 testt_stylus_beautify.sublime.settings
        config = self.get_config()

        # 将当前打开的文件进行格式化(需要格式匹配)
        if not self.has_selection():
            # 获取缓冲区内容
            # 如果是vue文件,提取 stye部分进行格式化
            if SYNTAX =='vue':
                region = self.get_vue_style_region()
                if not region:
                    return print('没有找到 style标签')

            elif SYNTAX == 'stylus':
                region = sublime.Region(0, self.view.size())

            # 将选区内容转换为字符串
            strBuffer = self.view.substr(region)

            # 将数据传给 comb 进行格式化
            combed = self.comb(strBuffer,config)
            if combed:
                #替换选区的内容为处理后的数据
                self.view.replace(edit, region, combed)
            return

        # 如果已有选区,则处理当前选区的内容
        for region in self.view.sel():
            if region.empty():
                continue

            # 将选区内容转换为字符串
            strBuffer = self.view.substr(region)

            combed = self.comb(strBuffer,config)
            if combed:
                print(combed)
                self.view.replace(edit, region, combed)


    # 格式化 stlus
    def comb(self, strBuffer, config):
        try:
            # 调用 nodejs
            # 传入一个列表 列表第一个元素时 nodjs
            p = Popen(['node', NODE_SCRIPT_PATH,config,SYNTAX], # 传入列表,自动生成空格隔开的格式
                stdout=PIPE,
                stdin=PIPE,
                stderr=PIPE,
                env=self.get_env(),
                shell=self.is_windows())#静默后台执行

        except OSError:
            raise Exception("Couldn't find Node.js. Make sure it's in your " +
                            '$PATH by running `node -v` in your command-line.')

        # 执行,同时指定返回接收的容器
        stdout, stderr = p.communicate(input=strBuffer.encode('utf-8'))

        if stdout:
            return stdout.decode('utf-8')
        else:
            sublime.error_message('出错啦: \n%s' % stderr.decode('utf-8'))

    ##
    ## @brief      返回vue 文件内 <style> 的内容
    ##
    ## @param      self  The object
    ##
    ## @return     The vue styls.
    ##
    def get_vue_style_region(self):
        start = self.view.find(r'^<style.*lang=[\'|\"]styl\w+[\'|\"].\w+>$',0)
        end = self.view.find(r'^<\/style>$',start.b)
        if start and end:
            return sublime.Region(start.b+1, end.a-1)
        return False

    # 判断已选择的缓冲区是否合法(有时候时多个,且不连续,那是不合法的)
    def has_selection(self):
        for sel in self.view.sel():
            start, end = sel
            if start != end:
                return True
        return False


    # 判断系统
    def is_osx(self):
        return platform.system() == 'Darwin'

    def is_windows(self):
        return platform.system() == 'Windows'

    # 如果时 osx 则将系统path 传入
    def get_env(self):
        env = None
        if self.is_osx():
            env = os.environ.copy()
            env['PATH'] += self.get_node_path()
        return env

    def get_settings(self):
        settings = self.view.settings().get('testt')
        if settings is None:
            settings = sublime.load_settings('stylusBeautify.sublime-settings')
        return settings

    def get_config(self):
        settings = self.view.settings().get('testt')

        if settings is None:
            settings = sublime.load_settings('testt.sublime-settings')

        if settings.has('stylus_beauty_options'):
            config = json.dumps(settings.get('stylus_beauty_options'))
            return config

    # 判断当前文件格式
    def is_target(self):
        if self.is_stylus():
            return 'stylus'

        if self.is_vue():
            return 'vue'

    def is_stylus(self):
        #通过 file_name 判断 stylus
        if self.view.file_name().endswith('.stylus') or self.view.file_name().endswith('.styl'):
            return True

        #通过 scope_name 判断是否 stylus
        if self.view.scope_name(0).startswith('source.stylus') or self.view.scope_name(0).startswith('source.styl'):
            return True

    def is_vue(self):
        #通过 file_name 判断 vue
        return self.view.file_name().endswith('.vue')